/*		Filename: 	net_manager.cpp
 *		Author:		彭望
 *		Date:		2012-01-12
 *		Use:		实现网络连接管理器
 */

#include "net_manager.h"

CNetManager::CNetManager(io_service& ios)
		:logger( Logger::getLogger() ),
		m_ios(ios),
		m_io_service_keeper_timer(m_ios),
		m_timer_period(boost::posix_time::seconds( 3600 * 24 )),
		m_acceptor(m_ios),
		m_resolver(m_ios),
		m_connSock( CNetManager::make_sock(m_ios) ),
		m_sendBuffer( CNetManager::make_buffer() ),
		m_recvBuffer( CNetManager::make_buffer() )

{
		logger.debug("Construct CNetManager");
}

/*调用任何函数前必须调用！！！
 *	彭望	2012.1.14
 */
RetCode_t CNetManager::init()
{
		m_io_service_keeper_timer.expires_from_now( m_timer_period );
		m_io_service_keeper_timer.async_wait( bind( &CNetManager::handle_io_service_keeper, 
								shared_from_this(), placeholders::error )
						);
		boost::thread(bind(&io_service::run, &m_ios));
		return RET_OK;
}

CNetManager::SockPtr CNetManager::make_sock(io_service& ios)
{
	return CNetManager::SockPtr( new CNetManager::sock_t(ios) );
}

CNetManager::BufferPtr CNetManager::make_buffer()
{
		return CNetManager::BufferPtr( new CNetManager::buffer_t() );
}

CNetManager::SessionIndex_t CNetManager::make_session_index(CNetManager::SockPtr sock)
{
		return CNetManager::SessionIndex_t( sock->remote_endpoint().address().to_string() );

}

RetCode_t CNetManager::start_accept(server_callback_func_t callback)
{
			SockPtr tmp = CNetManager::make_sock(m_ios);

			m_acceptor.async_accept(*(tmp.get()),
							bind(&CNetManager::handle_server_accept, shared_from_this(), 
									placeholders::error, callback, tmp)
							);
			logger.debug("sock counter : %ld", tmp.use_count());
			return RET_OK;
}

//用于服务器端监听消息
RetCode_t CNetManager::async_server_listen(const string& bind_ip, short port, 
				server_callback_func_t callback)
{
	logger.debug("in %s", __func__);
	endpoint ep(ip::address::from_string(bind_ip), port);
	error_code ec;

	try{
			const static size_t MAX_QUEUE_CLIENT = 10;
			m_acceptor.open( ep.protocol() );
			m_acceptor.set_option(socket_base::reuse_address(true));
					m_acceptor.bind(ep);
			m_acceptor.listen(MAX_QUEUE_CLIENT);
			this->start_accept(callback);
			

	}catch( const error_code& ec )
	{
			logger.warn("Bind failed! ip : %s, port : %u, error_msg : %s",
								bind_ip.c_str(), port, ec.message().c_str() );
			return RET_INVALID_ARG;
	}catch( exception& e )
	{
			logger.warn("Got exception in %s, %s", __func__, e.what());
			return RET_INVALID_ARG;
	}
	logger.info("Bind succeed! ip : %s, port : %u", bind_ip.c_str(), port);
	return RET_OK;
}

//用于服务器异步处理接收请求
void CNetManager::handle_server_accept(const error_code& ec, const server_callback_func_t& func, SockPtr sock)
{
		if( ec )
		{
				logger.warn("Error while accept, %s", ec.message().c_str() );
				return;
		}else{
				logger.debug("Accept succeed! client ip : %s, port : %u", sock->remote_endpoint().address().to_string().c_str(), sock->remote_endpoint().port());
				logger.debug("sock counter : %ld", sock.use_count());

				SessionIndex_t index = CNetManager::make_session_index( sock );

				
				//m_socks[index] = sock;

				m_recvBuffer->consume( m_recvBuffer->size() );
				mutable_buffers_1 buf = m_recvBuffer->prepare( CNetManager::MAX_MESSAGE_LENGTH );
				sock->async_receive(buf,
								bind(&CNetManager::handle_server_read, shared_from_this(),
								placeholders::error, placeholders::bytes_transferred, func, sock)
							 );
		}
}

//用于服务器异步读取数据
void CNetManager::handle_server_read(const error_code& ec, size_t bytes_transferred, const server_callback_func_t& callback, SockPtr sock)
{
		if( ec )
		{
				if( ec.value() == boost::system::errc::no_such_file_or_directory)
				{
						logger.info("EOF from client!");
						logger.debug("sock counter : %ld", sock.use_count());
				}else{
						logger.warn("Error while reading, %s, error_code : %d", ec.message().c_str(), ec.value());
				}
				this->start_accept(callback);
		}else{
				logger.debug("read %u bytes from client!", bytes_transferred);
				m_recvBuffer->commit( bytes_transferred );

				SessionIndex_t index = CNetManager::make_session_index( sock );
				
				this->handle_request( m_recvBuffer, m_sendBuffer, callback, index);

				const_buffers_1 buf = m_sendBuffer->data();
				sock->async_send(buf, 
								bind(&CNetManager::handle_server_write, shared_from_this(), 
										placeholders::error, placeholders::bytes_transferred, callback, sock)
								);
		}
}

//用于服务器异步发送数据
void CNetManager::handle_server_write(const error_code& ec, size_t bytes_transferred, server_callback_func_t callback, SockPtr sock)
{
	if( ec )
	{
		logger.warn("Error while writing, %s", ec.message().c_str());
		return;
	}else{
		logger.debug("Write %u bytes succeed!", bytes_transferred);
		m_sendBuffer->consume( m_sendBuffer->size() );
		m_recvBuffer->consume( m_recvBuffer->size() );
		mutable_buffers_1 buf = m_recvBuffer->prepare( CNetManager::MAX_MESSAGE_LENGTH );
		sock->async_receive(buf,
						bind(&CNetManager::handle_server_read, shared_from_this(),
						placeholders::error, placeholders::bytes_transferred, callback, sock)
					 );
	}
}

//用于服务器处理客户端逻辑请求
void CNetManager::handle_request(const BufferPtr& req, BufferPtr& res, const server_callback_func_t& func, const SessionIndex_t& index)
{
		string reqMsg( buffer_cast<const char*>( req->data() ), req->size() );
		std::istream is( req.get() );
		std::ostream os( res.get() );
		func(index, is, os);
}

//连接某个地址
RetCode_t CNetManager::connect(const string& server_ip, short server_listen_port, client_connect_callback_func_t callback)
{
		logger.debug("try to connect to %s:%u", server_ip.c_str(), server_listen_port);
		endpoint ep(ip::address::from_string(server_ip), server_listen_port);
		m_resolver.async_resolve( ep, 
						bind(&CNetManager::handle_client_resolve, shared_from_this(), 
								placeholders::error, placeholders::iterator, callback)
						);
		return RET_OK;
}

void CNetManager::handle_client_resolve(const error_code& ec, tcp::resolver::iterator iter, 
				client_connect_callback_func_t callback)
{
		async_connect(*m_connSock, iter, 
						bind(&CNetManager::handle_client_connect, shared_from_this(),
								placeholders::error, callback)
					 );
}
void CNetManager::handle_client_connect(const error_code& ec, client_connect_callback_func_t callback)
{
		if( ec )
		{
				logger.warn("connect error, %s", ec.message().c_str());
				callback(false);
				return;
		}else{
				logger.debug("connect to server succeed!");
				callback(true);
				return;
		}
}

void CNetManager::handle_client_write(const error_code& ec, size_t bytes_transferred, 
									const client_callback_func_t& callback)
{
		if( ec )
		{
				logger.warn("error while client write, %s", ec.message().c_str());
				return;
		}else{
				logger.debug("write %u bytes to server!", bytes_transferred);
				mutable_buffers_1 buf = m_recvBuffer->prepare( CNetManager::MAX_MESSAGE_LENGTH );
				m_connSock->async_receive(buf, 
								bind(&CNetManager::handle_client_read, shared_from_this(),
										placeholders::error, placeholders::bytes_transferred, callback)
								);
		}
}

void CNetManager::handle_client_read(const error_code& ec, size_t bytes_transferred, 
								const client_callback_func_t& callback)
{
		if( ec )
		{
				logger.warn("error while reading, %s", ec.message().c_str());
				return;
		}else{
				logger.debug("read %u bytes from server!", bytes_transferred);
				istream is( m_recvBuffer.get() );
				ostream os( m_sendBuffer.get() );
				callback(is, os);
		}
}

//向某个地址发送数据
//暂时不可重入!
RetCode_t CNetManager::send(const string& msg, const client_callback_func_t& callback)
{
		ostream os( m_sendBuffer.get() );
		os << msg;
		async_write(*m_connSock, *m_sendBuffer, 
						bind(&CNetManager::handle_client_write, shared_from_this(),
								placeholders::error, placeholders::bytes_transferred, callback)
						);
		return RET_OK;
}

void CNetManager::handle_io_service_keeper(const error_code& ec)
{
		if( ec )
		{
				logger.warn("handle_io_service_keeper error, %s", ec.message().c_str());
		}
		m_io_service_keeper_timer.expires_from_now( m_timer_period );
		m_io_service_keeper_timer.async_wait( bind( &CNetManager::handle_io_service_keeper, 
								shared_from_this(), placeholders::error )
						);

}
